package com.tarena.lbs.business.servcie.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.attach.pojo.dto.AttachDTO;
import com.tarena.lbs.attach.pojo.dto.AttachQrDTO;
import com.tarena.lbs.attach.pojo.param.AttachQRParam;
import com.tarena.lbs.attach.pojo.param.PicUpdateParam;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.model.Result;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.business.constant.BusinessTypes;
import com.tarena.lbs.business.dao.repository.BusinessRepository;
import com.tarena.lbs.business.dao.repository.StoreRepository;
import com.tarena.lbs.business.enums.BusinessResultEnum;
import com.tarena.lbs.business.openFeign.BasicClient;
import com.tarena.lbs.business.pojo.param.StoreParam;
import com.tarena.lbs.business.pojo.param.UserLocationParam;
import com.tarena.lbs.business.pojo.po.BusinessPO;
import com.tarena.lbs.business.pojo.po.StoreChainPO;
import com.tarena.lbs.business.pojo.po.StorePO;
import com.tarena.lbs.business.pojo.po.StoreSearchPO;
import com.tarena.lbs.business.pojo.query.AreaStoreQuery;
import com.tarena.lbs.business.pojo.query.StoreChainQuery;
import com.tarena.lbs.business.pojo.query.StoreQuery;
import com.tarena.lbs.business.pojo.vo.PictureVO;
import com.tarena.lbs.business.pojo.vo.StoreChainVO;
import com.tarena.lbs.business.pojo.vo.StoreVO;
import com.tarena.lbs.business.servcie.StoreService;
import com.tarena.lbs.business.source.BasicOutPutSource;
import com.tarena.lbs.common.enums.Roles;
import com.tarena.lbs.common.event.LocationEvent;
import com.tarena.lbs.common.principle.UserPrinciple;
import com.tarena.lbs.common.utils.AuthenticationContextUtils;
import com.tarena.lbs.common.utils.PageConverter;

import com.tarena.lbs.user.api.UserApi;
import com.tarena.lbs.user.api.pojo.dto.AdminDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.tarena.lbs.business.enums.BusinessResultEnum.*;

@Service
@Slf4j
public class StoreServiceImpl implements StoreService {
    @Autowired
    private StoreRepository storeRepository;
    @Autowired
    private BasicOutPutSource outputSource;
    @Autowired
    private BusinessRepository businessRepository;
    @DubboReference
    private UserApi userApi;
    @DubboReference
    private  AttachApi attachApi;
    @Autowired
    private BasicClient basicClient;



    // 门店列表前端可根据条件查询显示门店
    @Override
    public PageResult<StoreVO> storeList(StoreQuery query) throws BusinessException {
        log.info("查询商铺列表业务处理{}",query);
        //查询条件的依据应该是商户的id固定查询条件,其他条件附加
        //鉴权,校验角色及调用userApi获取用户对象
        AdminDto adminDto = getAdminDto();
        BusinessPO businessPO = businessRepository.busiStoreDetail(adminDto.getBusinessId());
        //若为空则该商家用户没有商户信息,即没有店铺
        query.setBusinessId(0);
        if(businessPO != null){
            log.debug("商户详情{}",businessPO);
            query.setBusinessId(businessPO.getId());
        }
        PageInfo<StorePO> pageInfo = storeRepository.pageList(query);
        //转换
        List<StorePO> storePOS = pageInfo.getList();
        List<StoreVO> storeVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(storePOS)){
           storeVOList= storePOS.stream().map(storePO -> {
               StoreVO storeVO = new StoreVO();
               storeVO.setUserId(adminDto.getId());
               BeanUtils.copyProperties(storePO,storeVO);
               return storeVO;
           }).collect(Collectors.toList());
        }
        return PageConverter.convert(pageInfo,storeVOList);
    }


    // 保存门店数据,用于新增门店数据
    @Override
    public void save(StoreParam param) throws BusinessException {
        log.info("保存店铺参数{}处理",param);
        //鉴权,校验角色及调用userApi获取用户对象
        AdminDto admin = getAdminDto();
        BusinessPO businessPO = businessRepository.busiStoreDetail(admin.getBusinessId());
        if(businessPO == null){
            throw new BusinessException(BUSINESS_NOT_EXISTS);
        }
        //将不一样或没有的属性赋值给StorePO对象的方法
        StorePO storePO = getStorePO(param);
        log.info("添加门店{}",storePO);
        storeRepository.add(storePO);
        log.info("添加成功");
        //添加门店成功后生成对应的门店二维码及链接,存入到storeChain数据库中
        storeLinkInsert(storePO, admin);
        //图片绑定
        bindPicture(param,storePO.getId());
    }


    //------------供内部调用-----------------
    //添加门店成功后生成对应的门店二维码及链接,存入到storeChain数据库中
    private void storeLinkInsert(StorePO storePO, AdminDto adminById) throws BusinessException {
        StoreChainPO storeChainPO = new StoreChainPO();
        AttachQRParam qrParam = new AttachQRParam();
        //添加二维码,返回路径及链接
        qrParam.setContent(storePO.toString());
        qrParam.setBusinessType(100);//店铺二维码
        qrParam.setBusinessId(adminById.getBusinessId());
        AttachQrDTO qrDTO = createQR(qrParam);
        //给链接表赋值
        storeChainPO.setCreateTime(new Date());
        storeChainPO.setStoreId(storePO.getId());
        storeChainPO.setLink(qrDTO.getUrl());
        storeChainPO.setLinkImage(qrDTO.getFileUuid());
        storeChainPO.setLinkStatus(1);//1启用,0禁用
        //赋值完毕后进行插入
        Boolean flag  = storeRepository.addStoreChain(storeChainPO);
        if(!flag){
            throw new BusinessException(STORE_CHAIN_ADD_ERROR);
        }
    }

    //------------供内部调用-----------------
    //将不一样或没有的属性赋值给StorePO对象
    private static @NotNull StorePO getStorePO(StoreParam param) {
        StorePO storePO = new StorePO();
        storePO.setCreateTime(new Date());
        storePO.setUpdateTime(new Date());
        storePO.setStoreLatitude(param.getLatitude());
        storePO.setStoreLongitude(param.getLongitude());
        List<String> storeImagesIds = param.getStoreImagesIds();
        if (CollectionUtils.isNotEmpty(storeImagesIds)){
            //拼接成字符串
            storePO.setStoreImagesId(String.join(",",storeImagesIds));
        }
        BeanUtils.copyProperties(param,storePO);
        return storePO;
    }

    //------------供内部调用-----------------
    //图片绑定的方法
    private void bindPicture(StoreParam param, Integer id) throws BusinessException {
        List<PicUpdateParam> picUpdateParamList = new ArrayList<>();
        //加入logo
        PicUpdateParam picUpdateLogo = new PicUpdateParam();
        picUpdateLogo.setBusinessId(id);
        picUpdateLogo.setBusinessType(200);
        picUpdateLogo.setFileUuid(UUID.randomUUID().toString());
        picUpdateParamList.add(picUpdateLogo);
        //加入营业执照
        List<String> storeImagesIds = param.getStoreImagesIds();
        storeImagesIds.forEach((imgs)->{
            PicUpdateParam picUpdateImgs = new PicUpdateParam();
            picUpdateImgs.setBusinessId(id);
            picUpdateImgs.setBusinessType(100);
            picUpdateImgs.setFileUuid(UUID.randomUUID().toString());
            picUpdateParamList.add(picUpdateImgs);
        });
        log.info("图片绑定参数{}",picUpdateParamList);
        Boolean b = attachApi.bathUpdateBusiness(picUpdateParamList);
        Asserts.isTrue(!b,new BusinessException(BusinessResultEnum.BINDING_FAILURE));
    }


    // 查询某区域内的门店
    @Override
    public PageResult<StoreVO> getStoreByCity(AreaStoreQuery query) throws BusinessException {
        log.info("查询城市{}下的门店",query);
        AuthenticationContextUtils.getUserPrinciple();
        PageInfo<StorePO> storePOS =  storeRepository.getStoreByCity(query);
        List<StorePO> storePOSList = storePOS.getList();
        List<StoreVO> storeVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(storePOSList)){
            storeVOList=storePOSList.stream().map(storePO -> {
                StoreVO storeVO = new StoreVO();
                BeanUtils.copyProperties(storePO,storeVO);
                return storeVO;
            }).collect(Collectors.toList());
        }
        return PageConverter.convert(storePOS,storeVOList);
    }


    // 手机小程序定位上报
    @Override
    public void reported(UserLocationParam param) throws BusinessException {
        UserPrinciple userPrinciple = AuthenticationContextUtils.getUserPrinciple();
        Integer userId = userPrinciple.getId();
        log.info("手机小程序定位上报{}",param);
        // 获取附近50公里内的店铺列表
        List<StoreSearchPO> list = storeRepository.getNearStore(param.getLatitude(),param.getLongitude(),50d);

        // 检查店铺列表是否为空
        if(CollectionUtils.isNotEmpty(list)){
            // 遍历每个店铺，处理位置事件
            list.forEach((store)->{
                // 创建一个位置事件对象
                LocationEvent event = new LocationEvent();
                // 设置用户ID
                event.setUserId(userId);
                // 设置店铺ID
                event.setStoreId(store.getId());
                // 构建消息对象
                Message<LocationEvent> message =
                        MessageBuilder.withPayload(event).build();
                // 发送消息到店铺位置输出通道
                outputSource.getStoreLocationOutput().send(message);
            });
        }
    }

    // 删除门店
    @Override
    public void delete(Integer id) throws BusinessException {
        log.info("删除门店入参{}",id);
        //鉴权,校验角色及调用userApi获取用户对象
        AdminDto adminDto = getAdminDto();
        //通过门店id和商家id删除门店
        storeRepository.delete(id,adminDto.getBusinessId());
        //删除门店成功关联进行删除门店的链接和二维码
        storeRepository.deleteStoreChainByStoreId(id);
    }

    //点击编辑时用于回显门店信息
    @Override
    public StoreVO selectById(Integer id) throws BusinessException {
        UserPrinciple userPrinciple = AuthenticationContextUtils.getUserPrinciple();
        log.info("查询店铺详情参数{}",id);
        StorePO storePO = storeRepository.getStoreById(id);
        StoreVO storeVO = new StoreVO();
        //此方法许可证图片id,image附件放入storeVO的图片列表字段PictureVOS中
        imagesMessageAdd(storePO, storeVO);
        //将Loge图片放入storeVO的storeLogoPic中
        logeImgsAdd(storePO, storeVO);
        //将当前用户ID传入storeVO中
        storeVO.setUserId(userPrinciple.getId());
        //将storePO中的相同属性复制给storeVO
        BeanUtils.copyProperties(storePO,storeVO);
        return storeVO;
    }

    //------------供内部调用-----------------
    //将Loge图片放入storeVO的storeLogoPic中
    private void logeImgsAdd(StorePO storePO, StoreVO storeVO) {
        String logoId = storePO.getStoreLogo();
        if (logoId != null && !logoId.isEmpty()) {
            AttachDTO attachDTO = attachApi.ByIdGatAttach(logoId);
            if (attachDTO != null){
                storeVO.setStoreLogoPic(attachDTO.getFileUuid());
            }
        }
    }

    //------------供内部调用-----------------
    //将许可证图片id,image附件放入storeVO的图片列表字段PictureVOS中的方法
    private void imagesMessageAdd(StorePO storePO, StoreVO storeVO) {
        String imagesIds = storePO.getStoreImagesId();
        log.info("图片id{}",imagesIds);
        List<Integer> imagesIdList = Arrays.stream(imagesIds.split(","))
                        .map(Integer::valueOf)
                        .collect(Collectors.toList());
        log.info("图片id集合{}",imagesIdList);
        if (!(imagesIdList.isEmpty())) {
            List<AttachDTO> attachDTOS = attachApi.selectAttachByIds(imagesIdList);
            List<PictureVO> pictureVOList = new ArrayList<>();
            if (attachDTOS != null && !attachDTOS.isEmpty()) {
                attachDTOS.forEach((attachDTO)->{
                    PictureVO pictureVO = new PictureVO();
                    pictureVO.setId(attachDTO.getId());
                    pictureVO.setImage(attachDTO.getFileUuid());
                    pictureVOList.add(pictureVO);
                });
            }
            log.info("attachDTOS{}",attachDTOS);
            log.info("pictureVOList{}",pictureVOList);
            storeVO.setPictureVOS(pictureVOList);
        }
    }


    //修改店铺信息
    @Override
    public void update(StoreParam param) {
        updateStoreMessage(param);
    }


    //启用
    @Override
    public void enable(Integer id) {
        log.info("门店启用/禁用入参{}",id);
        StoreParam storeParam = new StoreParam();
        storeParam.setId(id);
        //启用0停-1
        storeParam.setStoreStatus(0);
        updateStoreMessage(storeParam);
    }


    //禁用
    @Override
    public void disable(Integer id) {
        log.info("门店启用/禁用入参{}",id);
        StoreParam storeParam = new StoreParam();
        storeParam.setId(id);
        //启用0停-1
        storeParam.setStoreStatus(-1);
        updateStoreMessage(storeParam);
    }



    //------------供内部调用-----------------
    private void updateStoreMessage(StoreParam param) {
        log.info("修改门店参数{}", param);
        StorePO storePO = new StorePO();
        BeanUtils.copyProperties(param,storePO);
        //将没有对应的属性赋值
        // 将门店图片ID列表转换为逗号分隔的字符串并设置到门店信息对象中
        storePO.setStoreImagesId(StringUtils.join(param.getStoreImagesIds(),","));
        storePO.setStoreLongitude(param.getLongitude());
        storePO.setStoreLatitude(param.getLatitude());
        storePO.setUpdateTime(new Date());
        storeRepository.update(storePO);
    }



    //店铺链接
    @Override
    public PageResult<StoreChainVO> getChain(StoreChainQuery storeChainQuery) throws BusinessException {
        log.info("连锁店铺入参{}",storeChainQuery);
        //鉴权,校验角色及调用userApi获取用户对象
        AdminDto adminDto = getAdminDto();
        //使用商家Id查询,从从商家表中获取商家姓名
        BusinessPO businessPO = businessRepository.busiStoreDetail(adminDto.getBusinessId());
        //通过商家id,获取所用连锁店铺从门店表中获取门店名称,门店地址,门店Id
        List<StorePO> storePOS = storeRepository.selectStoreById(adminDto.getBusinessId());
        List<StoreChainPO> listPO = new ArrayList<>();
        //该方法作用是:循环遍历,将门店名称,门店地址,门店Id,商家名称,商家Id,省,市,县,赋值StoreChainPO中对应字段,将StoreChainPO对象添加到list集合中
        idHomologousArea(storePOS, businessPO, listPO);
        //创建PageResult对象,将listPO中的数据转换成StoreChainVO对象,并添加到listVO中
        //按照页码和页大小进行分页
        PageInfo<StoreChainPO> pageInfo = new PageInfo<>(listPO);
        pageInfo.setPageNum(storeChainQuery.getPageNo());
        pageInfo.setPageSize(storeChainQuery.getPageSize());
        List<StoreChainVO> listVO = listPO.stream().map(storeChainPO -> {
            StoreChainVO storeChainVO = new StoreChainVO();
            BeanUtils.copyProperties(storeChainPO,storeChainVO);
            return storeChainVO;
        }).collect(Collectors.toList());
        return PageConverter.convert(pageInfo,listVO);
    }

    //禁用店铺链接
    @Override
    public void disableChain(Integer id) {
        log.info("禁用店铺链接入参{}",id);
        StoreChainPO storeChainPO = new StoreChainPO();
        storeChainPO.setId(id);
        storeChainPO.setLinkStatus(0);
        storeRepository.updateChain(storeChainPO);
    }

    //启用店铺链接
    @Override
    public void enableChain(Integer id) {
        log.info("启用店铺链接入参{}",id);
        StoreChainPO storeChainPO = new StoreChainPO();
        storeChainPO.setId(id);
        storeChainPO.setLinkStatus(1);
        storeRepository.updateChain(storeChainPO);
    }

    //------------供内部调用-----------------
    //通过dubbo调用附件模块中生成二维码的工具类
    private AttachQrDTO createQR(AttachQRParam attachQRParam){
        AttachQrDTO attachQrDTO = attachApi.generateQrCode(attachQRParam);
        return attachQrDTO;
    }


    //------------供内部调用-----------------
    //鉴权,校验角色及调用userApi获取用户对象
    private @NotNull AdminDto getAdminDto() throws BusinessException {
        //校验角色
        UserPrinciple userPrinciple = AuthenticationContextUtils.getUserPrinciple();
        Asserts.isTrue(!(userPrinciple.getRole().equals(Roles.SHOP)), AUTH_NOT_EXISTS);
        //调用userApi获取商家Id
        AdminDto adminDto = userApi.getAdminById(userPrinciple.getId());
        Asserts.isTrue(adminDto == null, BUSINESS_NOT_EXISTS);
        return adminDto;
    }


    //------------供内部调用-----------------
    //循环遍历,将门店名称,门店地址,门店Id,商家名称,商家Id,省,市,县,赋值StoreChainPO中对应字段,将StoreChainPO对象添加到list集合中
    private void idHomologousArea(List<StorePO> storePOS, BusinessPO businessPO, List<StoreChainPO> listPO) {
        storePOS.forEach(storePO->{
            //通过门店Id查询相关的连锁门店信息
            StoreChainPO storeChainPO = null;
            try {
                storeChainPO = storeRepository.selectStoreChainById(storePO.getId());
            } catch (BusinessException e) {
                throw new RuntimeException(e);
            }
            storeChainPO.setStoreName(storePO.getStoreName());
            //拼接storePO中省,县,市作为门店详细地址
            List<Long> ids = new ArrayList<>();
            if (storePO.getProvinceId() != null){
                ids.add(Long.parseLong(storePO.getProvinceId()+""));
            }
            if (storePO.getCityId() != null){
                ids.add(Long.parseLong(storePO.getCityId()+""));
            }
            if (storePO.getAreaId() != null){
                ids.add(Long.parseLong(storePO.getAreaId()+""));
            }
            //从基础模块中调用,basicClient查询省,市,县名称
            Result<List<String>> areaNameList = basicClient.queryArea(ids);
            List<String> str = areaNameList.getData();
            //拼接为完整的字符串
            String storeAddress = StringUtils.join(str,"");
            storeChainPO.setBusinessName(businessPO.getBusinessName());
            storeChainPO.setStoreAddress(storeAddress);
            //添加到list集合中
            listPO.add(storeChainPO);
        });
    }
}
